using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using System;

namespace Mecee.EOL.Models {
    public class DownloadManager {
        private string url;
        private string destination;
        private int threads;

        public DownloadManager(string url, string destination, int threads) {
            this.url = url;
            this.destination = destination;
            this.threads = threads;
        }

        public async Task DownloadAsync() {
            using HttpClient client = new HttpClient();
            HttpResponseMessage response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
            long? contentLength = response.Content.Headers.ContentLength;
            if (contentLength.HasValue) {
                using (FileStream fileStream = new FileStream(destination, FileMode.Create, FileAccess.Write, FileShare.Write, 4096, true)) {
                    long part = contentLength.Value / threads;
                    List<Task> tasks = new List<Task>();
                    for (int i = 0; i < threads; i++) {
                        long rangeStart = i * part;
                        long rangeEnd = (i == threads - 1) ? contentLength.Value : rangeStart + part;
                        tasks.Add(DownloadPartAsync(client, fileStream, rangeStart, rangeEnd));
                    }
                    await Task.WhenAll(tasks);
                }
            }
        }

        private async Task DownloadPartAsync(HttpClient client, FileStream fileStream, long rangeStart, long rangeEnd) {
            using HttpRequestMessage request = new HttpRequestMessage();
            request.RequestUri = new Uri(url);
            request.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue(rangeStart, rangeEnd);
            HttpResponseMessage response = await client.SendAsync(request);
            byte[] bytes = await response.Content.ReadAsByteArrayAsync();
            lock (fileStream) {
                fileStream.Seek(rangeStart, SeekOrigin.Begin);
                fileStream.Write(bytes, 0, bytes.Length);
            }
        }
    }

}
